package cn.tedu.charging.user.service;

import cn.tedu.charging.common.constant.AppInfoConst;
import cn.tedu.charging.common.enums.VehicleUserBindEnum;
import cn.tedu.charging.common.pojo.param.ChargeParam;
import cn.tedu.charging.common.pojo.param.VehicleBindParam;
import cn.tedu.charging.common.pojo.param.VehicleUnbindParam;
import cn.tedu.charging.common.pojo.po.ChargingUserInfoPO;
import cn.tedu.charging.common.pojo.po.ChargingUserVehicleBindPO;
import cn.tedu.charging.common.pojo.po.ChargingVehiclePO;
import cn.tedu.charging.common.pojo.vo.VehicleVO;
import cn.tedu.charging.user.repository.UserRepository;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;

    @Override
    public Integer wxLogin(String nickName, String code) {
        // 1. 使用授权码，获取授权吴福气的openId
        String openId = getOpenId(code);
        log.debug("获取的openId:{}，授权码：{}", openId, code);
        // 2. 判断是否正确获取
        if (openId == null || openId.length() == 0) {
            log.error("获取openId失败!");
            throw new RuntimeException("获取openId失败!");
        }
        // 3. 根据openId，查询本地车主是否与其绑定
        ChargingUserInfoPO po = userRepository.getUserByOpenId(openId);
        // 4. 判断本地车主是否有绑定此openId的数据
        if (po == null) {
            // 5. 如果没有，则进行绑定，组织一个新的userinfo的po，补充必要属性，写入数据库，并且将新生成的po返回id
            po = new ChargingUserInfoPO();
            po.setWxOpenId(openId);
            po.setNickName(nickName);
            po.setCreateTime(new Date());
            po.setUpdateTime(new Date());
            userRepository.saveUser(po);
            // 如果是框架新增的po，在po的属性id上添加了自增注解，id会回填
        }
        return po.getId();
    }

    @Override
    public BigDecimal getBalance(Integer userId) {
        ChargingUserInfoPO po = userRepository.getUserById(userId);
        if (po != null) {
            return po.getBalance();
        }
        return null;
    }

    @Override
    public void charge(ChargeParam param) {
        ChargingUserInfoPO po = userRepository.getUserById(param.getUserId());
        if (po != null) {
            po.setBalance(po.getBalance().add(param.getAmount()));
            po.setUpdateTime(new Date());
            userRepository.saveUser(po);
        }
    }

    @Override
    public VehicleVO getUserBindedVehicle(Integer userId) {
        List<ChargingUserVehicleBindPO> pos = userRepository.getBindedVehicle(userId, VehicleUserBindEnum.BINDED.getState());
        VehicleVO vo = null;
        if (pos == null || pos.isEmpty()) {
            log.debug("用户没有绑定车辆");
        } else if (pos.size() == 1) {
            log.debug("用户绑定了1个车辆：{}", pos.get(0));
            Integer vehicleId = pos.get(0).getVehicleId();
            ChargingVehiclePO vpo = userRepository.getVehicleById(vehicleId);
            vo = new VehicleVO();  // 清空，重新封装
            BeanUtils.copyProperties(vpo, vo);
        } else {
            log.error("用户绑定了多个车辆!");
        }
        return vo;
    }

    @Override
    public Integer bindVehicle(VehicleBindParam param) {
        // 确定车辆信息，最好使用vechileId，但此处没有，所以使用车牌
        // 1. 查询正在进行绑定的车辆是否已经被用户绑定过了
        List<ChargingUserVehicleBindPO> vehicles = userRepository.getBindedVehicle(param.getUserId(), VehicleUserBindEnum.BINDED.getState());
        if (vehicles != null && !vehicles.isEmpty()) {
            log.error("用户正在绑定车辆!");
            throw new RuntimeException("用户正在绑定车辆!如需重新绑定，请先解绑");
        }
        checkVehicleInfo(param);  // 2. 调用相关单位接口，确认此车辆是否在现实中存在，此处留空，因为没有办法验证
        ChargingVehiclePO cvpo = userRepository.getVehicleByLicense(param.getLicense());
        if (cvpo == null) {
            // 3. 未绑定此车，新增该车辆的信息和该用户与之绑定的信息
            cvpo = new ChargingVehiclePO();
            BeanUtils.copyProperties(param, cvpo);
            cvpo.setCreateTime(new Date());
            cvpo.setUpdateTime(new Date());
            userRepository.saveVehicle(cvpo);
        }
        // 4. 生成绑定，有用户有车辆，只负责绑定两者id，并把绑定状态置为1
        // 保证如果解绑，绑定使用的id还是他们的
        userRepository.deleteUserBindVehicle(param.getUserId(),cvpo.getId());  // 先删除 绑定数据 不一定能删除数据 在绑定
        ChargingUserVehicleBindPO cvbpo = new ChargingUserVehicleBindPO();
        cvbpo.setUserId(param.getUserId());
        cvbpo.setVehicleId(cvpo.getId());
        cvbpo.setState(VehicleUserBindEnum.BINDED.getState());
        cvbpo.setCreateTime(new Date());
        userRepository.bindUserVehicle(cvbpo);
        return cvpo.getId();
    }

    @Override
    public void unbindVehicle(VehicleUnbindParam param) {
        ChargingUserVehicleBindPO cvbpo = new ChargingUserVehicleBindPO();
        cvbpo.setUserId(param.getUserId());
        cvbpo.setVehicleId(param.getVehicleId());
        userRepository.unbindUserVehicle(cvbpo);
    }

    // 其他单位（如：车管所）验证车辆真实信息的接口
    private void checkVehicleInfo(VehicleBindParam param) {
    }

    private String getOpenId(String code) {
        // 1. 按照官方文档拼接参数并发起请求
        RestTemplate restTemplate = new RestTemplate();
        String url = "https://api.weixin.qq.com/sns/jscode2session?appid={1}&secret={2}&js_code={3}&grant_type=authorization_code";
        // 2. 解析响应体，封装一个对象接受WxOpenIdDto
        String wxLoginJson = restTemplate.getForObject(url, String.class, AppInfoConst.APP_ID, AppInfoConst.APP_SECRET, code);
        // 3. 利用fastjson工具解析成JSONObject(key=value)，从而获取id
        JSONObject jsonObject = JSON.parseObject(wxLoginJson);
        return jsonObject.getString("openid");
    }
}
